use std::collections::HashMap;
use crate::{code, mdb::{self, gridfs_file}, query};
use axum::Json;
use futures_util::{io::AsyncReadExt, AsyncWriteExt};
use mongodb::options::{GridFsBucketOptions, GridFsUploadOptions };
use serde_json::{json, Value};

use super::gridfs_delete;
const DBNAME:&str = "fx";
// 解析 bucket_name
pub fn get_bucket_name_classify(bucket_name:&str) -> Result<HashMap<&str, &str>, Json<Value>>{
    let mut obj:HashMap<&str, &str> = HashMap::new();
    if  bucket_name.is_empty() {
        obj.insert("bucket_name", DBNAME);
        obj.insert("classify", &"");
    } else if bucket_name.starts_with("_"){ // _type
        let type_name = bucket_name.strip_prefix("_").unwrap_or_default();
        obj.insert("bucket_name", DBNAME);
        obj.insert("classify", type_name);
    } else if bucket_name.contains("_"){ // name_type
        let arr = bucket_name.split("_").collect::<Vec<&str>>();
        obj.insert("bucket_name", arr[0]);
        obj.insert("classify", arr[1]);
    }else{
        obj.insert("bucket_name", bucket_name);
        obj.insert("classify", &"");
    }
    return Ok(obj)
}
pub fn get_bucket_name(bucket_name:&str) -> Result<String, Json<Value>>{
   if bucket_name.is_empty() || bucket_name.starts_with("_") { // _type
        Ok(DBNAME.to_owned())
    } else if bucket_name.contains("_"){ // name_type
        let arr = bucket_name.split("_").collect::<Vec<&str>>();
        Ok(arr[0].to_owned())
    }else{
        Ok(bucket_name.to_owned())
    }
}
// 获取文件内容
pub async fn move_file(object_id:&str, bucket_name:&str) -> Result<(), Json<Value>>{
    let id = mdb::to_object_id(object_id.to_owned());

    let obj = get_bucket_name_classify(bucket_name)?;
    let bucket_name = obj.get("bucket_name").unwrap_or(&DBNAME);
    let conn = mdb::connect().await?;
    // 从一个桶下载文件
    let options = GridFsBucketOptions::builder().build();
    let bucket = conn.gridfs_bucket(options);
    let doc = gridfs_file::find::get_info_( id.to_owned(), bucket.to_owned()).await?;
    let dest_options = GridFsBucketOptions::builder().bucket_name(bucket_name.to_string()).build();
    let dest_bucket = conn.gridfs_bucket(dest_options);
     // 将下载文件移入到新的桶
    match bucket.open_download_stream(id.to_owned()).await {
        Ok(mut stream) => {
            let meta = match doc.metadata {
                Some(mut f) => {
                    f.remove("temp");
                    f.insert("bucket", bucket_name);
                    if let Some(c) =  obj.get("classify") { f.insert("classify", c); }
                    Some(f)
                },
                None => None
            };
            let mut buf = Vec::new();

            // 将 fs 中的文件上传到 fx 中，并删除 fs 中的文件
            let upload_options = GridFsUploadOptions::builder().metadata(meta).build();

            match dest_bucket.open_upload_stream( doc.filename.unwrap_or_default()).with_options(upload_options).id(doc.id).await {
                Ok(mut f) => {
                    if let Ok(_) = stream.read_to_end(&mut buf).await {
                        if let Ok(_) = f.write(&buf).await {
                            _ = f.close().await.unwrap_or_default();
                        }
                    }
                    gridfs_delete::one(object_id, "fs").await?;
                    Ok(())
                },
                Err(e) => Err(code::sys_(e.to_string()))
            }
        },
        Err(e) => Err(code::sys_(e.to_string()))
    }
   
    
}
// 移动文件并返回固定 url
pub async fn upload(body:&Value, field:&str, bucket_name:&str) -> Result<String, Json<Value>> {
    let rs = get_upload_url(&query::str(body, field)?, bucket_name).await;
    delete_file_old(body, field, bucket_name).await?;
    rs
}
pub async fn upload_op(body:&Value, field:&str, bucket_name:&str) -> Result<Option<String>, Json<Value>> {
    let url = query::str_op(body, field)?;
    if let Some(f) = url {
        let rs = get_upload_url(&f, bucket_name).await?;
        delete_file_old(body, field, bucket_name).await?;
        Ok(Some( rs ))
    }else{
        delete_file_old(body, field, bucket_name).await?;
        Ok(None)
    }
}
pub async fn get_upload_url(url:&str, bucket_name:&str) -> Result<String, Json<Value>> {
    if url.contains("temp/") {
        let id = get_temp_id(&url)?;
        let url = get_url(&url, bucket_name)?;
        move_file(&id, &bucket_name).await?;
        Ok(url)
    }else {
        Ok(url.to_owned())
    }
}
pub async fn delete_file_old(body:&Value, field:&str, bucket_name:&str) -> Result<(), Json<Value>> {
    if let Some(f) = query::str_op(body, &format!("{}_old", field))?{
        let obj = parse_url(&f)?;
        if let Some(id) = obj.get("id"){
            gridfs_delete::one(id,bucket_name).await.unwrap_or_default();
        }
    }
    Ok(())
}
// 多文件上传
pub async fn uploads(body:&Value, field:&str, bucket_name:&str) -> Result<Value, Json<Value>>{
    let rs = get_uploads_url(query::json(body, field)?, bucket_name).await;
    delete_files_old(body, field, bucket_name).await?;
    rs
}
pub async fn uploads_op(body:&Value, field:&str, bucket_name:&str) -> Result<Option<Value>, Json<Value>>{
    let url = query::json_op(body, field)?;
    match url {
        Some(f) => {
            let rs = get_uploads_url(f, bucket_name).await?;
            delete_files_old(body, field, bucket_name).await?;
            Ok(Some(rs))
        },
        None => {
            delete_files_old(body, field, bucket_name).await?;
            Ok(None)
        }
    }
}
pub async fn get_uploads_url(url:Value, bucket_name:&str) -> Result<Value, Json<Value>>{
    if url.is_null() {
        return Ok(json!([]))
    }
    match url.as_array() {
        Some(url_arr) => {
            if url_arr.len() == 0 {
                return Ok(json!([]))
            }
            let mut vec: Vec<String> = Vec::new();
            for v in url_arr {
                if let Some( s ) = v.as_str() {
                    if s.contains("temp/") {
                        let id = get_temp_id(s)?;
                        move_file( &id, bucket_name ).await?;
                        vec.push(get_url(s, bucket_name)?);
                    }else {
                        vec.push(s.to_owned());
                    }
                }
            }
            
            Ok( json!(vec) )
        },
        None => Ok(json!([]))
    }
}
pub async fn delete_files_old(body:&Value, field:&str, bucket_name:&str) -> Result<(), Json<Value>> {
    if let Some(f) = query::json_op(body, &format!("{}_old", field))?{
        if let Some(old) = f.as_array(){
            for v in old {
                if let Ok(obj) = parse_url(v.as_str().unwrap_or_default()){
                    if let Some(id) = obj.get("id"){
                        gridfs_delete::one(id,bucket_name).await.unwrap_or_default();
                    }
                }
            }
        }
    }
    Ok(())
}
// 移动文件并返回 objectid
pub async fn upload_id(body:&Value, field:&str, bucket_name:&str) -> Result<String, Json<Value>> {
    let id = query::str(body, field)?;
    move_file(&id, bucket_name).await?;
    Ok(id)
}
pub async fn upload_id_op(body:&Value, field:&str, bucket_name:&str) -> Result<Option<String>, Json<Value>> {
    let id = query::str_op(body, field)?;
    if let Some(f) = id {
        move_file(&f, bucket_name).await?;
        Ok(Some(f))
    }else{
        Ok(None)
    }
}
//解析 url = bucket_name/objectid.type
pub fn parse_url(url:&str) -> Result<HashMap<&'static str,String>, Json<Value>> {
    if url.is_empty() {
        return Err(code::err_("访问文件路径不存在！"))
    }
    let mut obj:HashMap<&str,String> = HashMap::new();

    let msg = "访问文件路径格式不正确！";
    let mut url = String::from(url);
    
    let is_temp = url.contains("temp/");
    if  is_temp { url = url.to_owned().replace("temp/", "") };
    
    if url.contains("/") {
        let d = url.split("/").collect::<Vec<&str>>();

        if let Some(f) = d.get(0)  {
            obj.insert("bucket", if is_temp { "fs".to_owned() } else { f.to_string() });
        }else{
            return Err(code::err_(msg))
        }

        if let Some(f) = d.get(1){
            let v = f.split(".").collect::<Vec<&str>>();
            if let Some(d) = v.get(0) {
                obj.insert("id", d.to_string());
            }else {
                return Err(code::err_(msg))
            }
            if let Some(d) = v.get(1) {
                obj.insert("type", d.to_string());
            }else {
                return Err(code::err_(msg))
            }
        }else{
            return Err(code::err_(msg))
        }
    }else{
        let v = url.split(".").collect::<Vec<&str>>();
        obj.insert("bucket", if is_temp { "fs".to_owned() } else { DBNAME.to_owned() });
        if let Some(d) = v.get(0) {
            obj.insert("id", d.to_string());
        }else {
            return Err(code::err_(msg))
        }
        if let Some(d) = v.get(1) {
            obj.insert("type", d.to_string());
        }else {
            return Err(code::err_(msg))
        }
    }
    Ok(obj)
}
// 从 url 获取 id = bucket_name/objectid.type
pub fn get_temp_id(url:&str) -> Result<String, Json<Value>> {
    if url.is_empty() {
        return Err(code::err_("访问文件路径不存在！"))
    }
    let str;

    let msg = "访问文件路径格式不正确！";

    let url = url.replace("temp/", "");

    let d = url.split(".").collect::<Vec<&str>>();

    if let Some(f) = d.get(0){
        str = f.to_string();
    }else{
        return Err(code::err_(msg))
    }
    Ok(str)
}
// 获取最终 url
pub fn get_url(url:&str, bucket_name:&str) -> Result<String, Json<Value>> {
    if let Some(f) = get_url_op( Some(url.to_owned()), bucket_name )? {
        Ok(f)
    }else{
        Err( code::err_(format!("url: {url} 解析不能为空")) )
    }
}
pub fn get_url_op(url:Option<String>, bucket_name:&str) -> Result<Option<String>, Json<Value>> {
    if let Some(f) = url {
        let url = f.replace("temp/", "");
        if bucket_name.starts_with("_") || bucket_name.is_empty() { // _type
            Ok( Some(url) )
        } else if bucket_name.contains("_"){ // name_type
            let arr = bucket_name.split("_").collect::<Vec<&str>>();
            Ok(Some(arr[0].to_owned() + "/" + &url))
        }else{
            Ok(None)
        }
    }else{
        Ok(None)
    }
}
// 以 url 删除
pub async fn delete_file_url(url:&str) -> Result<(), Json<Value>> {
    let obj = parse_url(url)?;
    if let Some(id) = obj.get("id"){
        gridfs_delete::one(id,obj.get("bucket").unwrap_or(&DBNAME.to_owned())).await.unwrap_or_default();
    }
    Ok(())
}
pub async fn delete_files_url(url:Vec<String>) -> Result<(), Json<Value>> {
    for v in url {
        if let Ok(obj) = parse_url(&v){
            if let Some(id) = obj.get("id"){
                gridfs_delete::one(id, obj.get("bucket").unwrap_or(&DBNAME.to_owned())).await?;
            }
        }
    }
    Ok(())
}